#! /usr/bin/env python
# -*- coding: UTF-8 -*-
# Applet for uploading images to Imageshack.us

__license__ = "GNU General Public License v.2"
__version__ = "0.4"
__author__ = "Cyxapeff <max@cyxapeff.org>"

import pygtk
pygtk.require('2.0')
import sys, os
import gtk
import gnome.ui
import gnomeapplet

import urllib
import Image

gtk.gdk.threads_init()

from gconfclient import ImageshackGconfClient
from services_manager import Services 
from history import History

from ui.result import ResultWindow
from ui.settings import SettingsWindow
from ui.history import HistoryDialog

import pickle

import gettext
gettext.install('messages',  os.path.join(os.path.dirname(os.path.abspath(__file__)), "locale"), unicode=True)

class Codes():
    data = []
    
    def load(self, filename):
        try:
            pkl_file = open(filename, 'rb')
            self.data = pickle.load(pkl_file)
            pkl_file.close()
        except:
            print "No codes"
        
    def save(self, filename):
        pkl_file = open(filename, 'wb')
        pickle.dump(self.data, pkl_file)
        pkl_file.close()
        
    def get_by_label(self, label):
        i = 0
        for c in self.data:
            if c['label'] == label:
                return (i, c)
            i += 1

def check_image(filename):
    try:
        im = Image.open(filename)
        return True
    except:
        return False
        
def raw_to_jpeg(filename):
    try:
        im = Image.open(filename)
        im.save("/tmp/jpeg.jpg","jpeg")
    except:
        return None
    return "/tmp/jpeg.jpg"

class GnomeAppletImageshack(gnomeapplet.Applet):

    # Main applet window

    def __init__(self, applet, iid):
        self.gconf = ImageshackGconfClient(
                        callback=self._cb_gconf_change_display,
                        callback2=self._cb_gconf_change_service)
        self.services = Services()
        
        self.display = self.gconf.get_display()
        self.service = self.services.modules[self.gconf.get_service()]
        
        self.codes = Codes()
        self.codes.load(os.path.join(os.path.dirname(__file__), 'codes.pkl'))
        
        self.history = History(os.path.join(os.path.dirname(__file__), 'history'))
                
        self.applet = applet
        self.__init_core_widgets()
        self.init_additional_widgets()
        self.init_ppmenu()
        self.__connect_events()
        self.applet.connect("destroy", self._cleanup)
        self.after_init()
        self.applet.show()

    def __init_core_widgets(self):
        """Create internal widgets"""
        self.tooltips = gtk.Tooltips()
        self.hbox = gtk.HBox()
        self.ev_box = gtk.EventBox()
        self.ev_box.show()
        self.applet.add(self.hbox)
        self.hbox.add(self.ev_box)
        self.hbox.show()

    def init_additional_widgets(self):
        """Create additional widgets"""
        self.innerhbox = gtk.HBox(False, 2)
        size = self.applet.get_size()
        self.image = gtk.Image()
        pixbuf = gtk.gdk.pixbuf_new_from_file("/usr/share/gnome-panel/pixmaps/imageshack.png")
        scaled_buf = pixbuf.scale_simple(size,size,gtk.gdk.INTERP_BILINEAR)
        self.image.set_from_pixbuf(scaled_buf)
        self.innerhbox.add(self.image)
        self.label = gtk.Label("Host It!")
        self.innerhbox.add(self.label)
        self.innerhbox.show()
        if self.display == 1 or self.display == 0:
            self.image.show()
        if self.display == 2 or self.display == 0:
            self.label.show()
        self.ev_box.add(self.innerhbox)

    def init_ppmenu(self):
        """Create popup menu for properties"""
        self.ppmenu_xml = _("""
        <popup name="button3">
        <menuitem name="History Item" verb="History" label="History"/>
        <menuitem name="Preferences Item" verb="Preferences" stockid="gtk-properties"/>
        <menuitem name="About Item" verb="About" stockid="gtk-about"/>
        </popup>        
        """)
        self.ppmenu_verbs = [("History", self.on_ppm_history),
            ("Preferences", self.on_ppm_preferences),
            ("About", self.on_ppm_about),
            ]

    def __connect_events(self):
        """Connect applet's events to callbacks"""
        self.ev_box.connect("button-press-event", self.on_button)
        self.ev_box.connect("enter-notify-event", self.on_enter)
        self.button_actions = {
            1: self._show_chooser_window,
            2: self._get_screenshot,
            3: self._show_ppmenu,
            }
        self.ev_box.connect('drag_data_received', self.on_drag_data_received)
        dnd_list = [ ( 'text/uri-list', 0, 80 ) ]
        self.ev_box.drag_dest_set( gtk.DEST_DEFAULT_MOTION |
		        gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_DROP,
		        dnd_list, gtk.gdk.ACTION_COPY)

    def after_init(self):
        """After-init hook"""
        pass
        
    def _cb_gconf_change_display(self, client, cnxn_id, entry, params):
        self.display = self.gconf.get_display()
        self.image.hide()
        self.label.hide()
        if self.display == 1 or self.display == 0:
            self.image.show()
        if self.display == 2 or self.display == 0:
            self.label.show()
            
    def _cb_gconf_change_service(self, client, cnxn_id, entry, params):
        self.service = self.services.modules[self.gconf.get_service()]

    def _cleanup(self, event):
        """Cleanup callback (on destroy)"""
        del self.applet

    def on_button(self, widget, event):
        """Action on pressing button in applet"""
        if event.type == gtk.gdk.BUTTON_PRESS:
            if event.state & gtk.gdk.SHIFT_MASK:
                self.button_actions[2]()
            else:
                self.button_actions[event.button]()

    def _show_ppmenu(self):
        """Show popup menu"""
        self.applet.setup_menu(self.ppmenu_xml,
                               self.ppmenu_verbs,
                               None)

    def on_enter(self, widget, event):
        """Action on entering mouse to widget"""
        info = _("Host it")
        self.tooltips.set_tip(self.ev_box, info)

    def on_ppm_about(self, event, data=None):
        """Action on chose 'about' in pop-up menu"""
        pixbuf = gtk.gdk.pixbuf_new_from_file("/usr/share/gnome-panel/pixmaps/imageshack.png")
        description = _("Applet for uploading images to Imageshack.us\nWebsite: http://cyxapeff.org")
        about = gnome.ui.About("GnomeApplet Imageshack", __version__, 
                       __license__,
                       description,
                       [__author__,"Thanks Pythy for applet skeleton"],
                       None, None,
                       pixbuf).show()
                       
    def on_ppm_preferences(self, event, data=None):
        window = SettingsWindow(self.gconf, self.codes)
        window.make(self.display, self.services, self.service)

    def on_ppm_history(self, event, data=None):
        dialog = HistoryDialog(self.history, self.codes)
        dialog.make()

    def upload(self, filename):
        name, ext = os.path.splitext(filename)
        #if ext == ".raw":
        #    filename = raw_to_jpeg(filename)
        if not filename is None:         
            obj = ResultWindow(self.codes)
            obj.uploading()
            core = self.service(obj, filename, self.history)
            core.start()
   
    # Chooser window
        
    def __init_chooser_window(self):
        preview = gtk.Image()
        self.chooser = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_OPEN,
            buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
        self.chooser.set_current_folder(os.environ['HOME'])
        self.chooser.set_default_response(gtk.RESPONSE_OK)
        self.chooser.set_preview_widget(preview)
        self.chooser.connect("update-preview", self.update_preview_cb, preview)
        
        filter = gtk.FileFilter()
        filter.set_name(_("Images"))
        filter.add_mime_type("image/png")
        filter.add_mime_type("image/jpeg")
        filter.add_mime_type("image/gif")
        filter.add_pattern("*.png")
        filter.add_pattern("*.jpg")
        filter.add_pattern("*.gif")
        self.chooser.add_filter(filter)
        
        filter2 = gtk.FileFilter()
        filter2.set_name("All files")
        filter2.add_pattern("*")
        self.chooser.add_filter(filter2)
        
    def __destroy_chooser_window(self, event):
        self.chooser.destroy()
        
    def _show_chooser_window(self):       
        self.__init_chooser_window()
        response = self.chooser.run()
        if response == gtk.RESPONSE_OK:
            filename = self.chooser.get_filename()
            self.chooser.destroy()
            if os.path.isfile(filename) and check_image(filename):
                self.upload(filename)
        else:
            self.chooser.destroy()
            
    def update_preview_cb(self, file_chooser, preview):
        filename = file_chooser.get_preview_filename()
        try:
            pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(filename, 150, 150)
            preview.set_from_pixbuf(pixbuf)
            have_preview = True
        except:
            have_preview = False
        file_chooser.set_preview_widget_active(have_preview)
            
    # Drag&Drop

    def get_file_path_from_dnd_dropped_uri(self, uri):
        path = urllib.url2pathname(uri) # escape special chars
        path = path.strip('\r\n\x00') # remove \r\n and NULL

        # get the path to file
        if path.startswith('file:\\\\\\'): # windows
	        path = path[8:] # 8 is len('file:///')
        elif path.startswith('file://'): # nautilus, rox
	        path = path[7:] # 7 is len('file://')
        elif path.startswith('file:'): # xffm
	        path = path[5:] # 5 is len('file:')
        return path

    def on_drag_data_received(self, widget, context, x, y, selection, target_type, timestamp):
        TARGET_TYPE_URI_LIST = 80
        if target_type == TARGET_TYPE_URI_LIST:
            uri = selection.data.strip()
            uri_splitted = uri.split() # we may have more than one file dropped
            for uri in uri_splitted:
                path = self.get_file_path_from_dnd_dropped_uri(uri)
                if os.path.isfile(path) and check_image(path): # is it file?
                    self._dialog(path)
                    
    def _dialog(self, filename):
        dialog = gtk.Dialog(title=_("Are you sure?"), parent=None,
                    flags=gtk.DIALOG_MODAL,
                    buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                    gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
        hbox = gtk.HBox(spacing=5)
        image = gtk.Image()
        pixbuf = gtk.gdk.pixbuf_new_from_file(filename)
        width = int((70.0/pixbuf.get_height())*pixbuf.get_width())
        scaled_buf = pixbuf.scale_simple(width,70,gtk.gdk.INTERP_BILINEAR)
        image.set_from_pixbuf(scaled_buf)
        hbox.pack_start(image, True, True, 0)
        image.show()
        label = gtk.Label(_("Are you sure upload\n%s?") % filename)
        hbox.pack_start(label, True, True, 0)
        label.show()
        dialog.vbox.set_spacing(5)
        dialog.vbox.pack_start(hbox)
        hbox.show()
        response = dialog.run()
        if response == gtk.RESPONSE_ACCEPT:
            dialog.destroy()
            self.upload(filename)
        else:
            dialog.destroy()        

    # Others

    def _get_screenshot(self):
        w = gtk.gdk.get_default_root_window()
        sz = w.get_size()
        pb = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB,False,8,sz[0],sz[1])
        pb = pb.get_from_drawable(w,w.get_colormap(),0,0,0,0,sz[0],sz[1])
        if (pb != None):
            pb.save("/tmp/screenshot.png","png")
            self.upload("/tmp/screenshot.png")
        else:
            print "Unable to get the screenshot."

def applet_factory(applet, iid):
    GnomeAppletImageshack(applet, iid)
    return True

def run_in_panel():
    gnomeapplet.bonobo_factory("OAFIID:GNOME_AppletImageshack_Factory",
                               GnomeAppletImageshack.__gtype__,
                               "Applet Imageshack",
                               "0",
                               applet_factory)


def run_in_window():
    main_window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    main_window.set_title("GNOME Applet Imageshack")
    main_window.connect("destroy", gtk.main_quit)
    app = gnomeapplet.Applet()
    applet_factory(app, None)
    app.reparent(main_window)
    main_window.show()
    gtk.main()
    sys.exit()

def main(args):
    if len(args) == 2 and args[1] == "--run-in-window":
        run_in_window()
    else:
        run_in_panel()

if __name__ == '__main__':
    main(sys.argv)
